#ifndef MERSENNE_TWISER_HPP
#define MERSENNE_TWISER_HPP

#include <array>

class MersenneTwister
{
public:
	MersenneTwister()
	{
		Seed(DEFAULT_SEED);
	}

	void Seed(unsigned long seed)
	{
		state[0] = seed & 0xFFFFFFFFUL; 
		for (int i = 1; i < STATE_SIZE; ++i) 
		{
			state[i] = 1812433253UL * (state[i - 1] ^ (state[i - 1] >> 30)) + i;
			state[i] &= 0xFFFFFFFFUL;
		}
		position = STATE_SIZE;
	}

	double operator()()
	{
		return Next();
	}

	double Next() 
	{
		return static_cast<double>(NextInt32()) * (1. / 4294967296.);
	}

private:
	unsigned long NextInt32()
	{
		if (position == STATE_SIZE) 
			GenerateState();

		unsigned long x = state[position++];
		x ^= (x >> 11);
		x ^= (x << 7) & 0x9D2C5680UL;
		x ^= (x << 15) & 0xEFC60000UL;
		return x ^ (x >> 18);
	}

	void GenerateState() 
	{ 
		for (int i = 0; i < (STATE_SIZE - MIDDLE_WORD); ++i)
			state[i] = state[i + MIDDLE_WORD] ^ 
				Twiddle(state[i], state[i + 1]);

		for (int i = STATE_SIZE - MIDDLE_WORD; i < (STATE_SIZE - 1); ++i)
			state[i] = state[i + MIDDLE_WORD - STATE_SIZE] ^ 
				Twiddle(state[i], state[i + 1]);

		state[STATE_SIZE - 1] = state[MIDDLE_WORD - 1] ^ 
			Twiddle(state[STATE_SIZE - 1], state[0]);
		position = 0;
	}

	unsigned long Twiddle(unsigned long u, unsigned long v) 
	{
		return (((u & 0x80000000UL) | (v & 0x7FFFFFFFUL)) >> 1) ^ 
			((v & 1UL) ? 0x9908B0DFUL : 0x0UL);
	}

	static_assert(sizeof(unsigned long) == 4, "32 bit error");

	static const size_t STATE_SIZE = 624;
	static const size_t MIDDLE_WORD = 397;
	static const unsigned long DEFAULT_SEED = 5489U;

	std::array<unsigned long, STATE_SIZE> state;
	size_t position;
};


#endif  // MERSENNE_TWISER_HPP
